import java.util.TreeMap;


public class Box implements Comparable<Box> {
	Coord position;
	private TreeMap<Character, StringBuffer> instructionLists;
	private boolean visited = false;
	
	public boolean isVisited() {
		return visited;
	}
	
	public void markAsVisisted() {
		visited = true;
	}
	
	public Box(Coord c) {
		//Coord c = b.getCoord();
		this.position=new Coord(c.x, c.y);
	}
	
	public void eraseMemory() {
		visited=false;
		instructionLists.clear();
	}
	
	public TreeMap<Character, StringBuffer> getInstructionLists() {
		return instructionLists;
	}
	
	public StringBuffer getAndRemoveInstructionList(char identifier) {
		return instructionLists.remove(identifier);
	}
	
	public void removeInstructionList(char identifier) {
		//instructionLists.remove(identifier);
	}
	
	public StringBuffer getInstructionList(char identifier) {
		return instructionLists.get(identifier);
	}
	
	public void addInstructionList(StringBuffer instructionList, char identifier) {
		if (instructionLists==null) instructionLists = new TreeMap<Character, StringBuffer>();
		instructionLists.put(identifier, instructionList);
	}
	
	public TileList getSurroundingTiles() {
		//Should return tiles in some clever way
		int x   = position.x;
		int y   = position.y;
		
		
		TileList surroundingTiles   = new TileList();
		

		Coord tileNorth   = new Coord(x,y+1);
		Coord tileSouth   = new Coord(x,y-1);
		Coord tileWest    = new Coord(x-1,y);
		Coord tileEast    = new Coord(x+1,y);
	
		StaticMap s = StaticMap.getStaticMap();
		
		if (s.isTileEmpty(tileNorth)) surroundingTiles.add(tileNorth);		
		if (s.isTileEmpty(tileSouth)) surroundingTiles.add(tileSouth);
		if (s.isTileEmpty(tileWest)) surroundingTiles.add(tileWest);
		if (s.isTileEmpty(tileEast)) surroundingTiles.add(tileEast);
		

		return surroundingTiles;
	}
	
	/**
	 * A box can only be moved if it has empty tiles either horizontally or vertically
	 * @return Surrounding tiles from where the man can push the box
	 */
	public TileList getSurroundingPushableTiles(BoxList boxList) {
		//Should return tiles in some clever way
		int x   = position.x;
		int y   = position.y;
		
		
		TileList surroundingTiles   = new TileList();
		

		Coord tileNorth   = new Coord(x,y-1);
		Coord tileSouth   = new Coord(x,y+1);
		Coord tileWest    = new Coord(x-1,y);
		Coord tileEast    = new Coord(x+1,y);
	
		StaticMap s = StaticMap.getStaticMap();
		
		if (isTileEmptyForVerticalMove(boxList, x, y)) {
			surroundingTiles.add(tileSouth);
		}
		if (isTileEmptyForHorizontalMove(boxList, x, y)) {
			surroundingTiles.add(tileWest);	
		}
		if (isTileEmptyForVerticalMove(boxList, x, y)) {
			surroundingTiles.add(tileNorth);	
		}
		if (isTileEmptyForHorizontalMove(boxList, x, y)) {
			surroundingTiles.add(tileEast);
		}

 /*
		for(Coord c : surroundingTiles) {
			System.out.println("( " + c.x + ", " + c.y + ")");
		}
*/
	//	System.out.println("");
		return surroundingTiles;
	}
	
	public boolean isTileEmptyForVerticalMove(BoxList boxList, int x, int y) {
		Coord tileNorth   = new Coord(x,y-1);
		Coord tileSouth   = new Coord(x,y+1);
		
		StaticMap s = StaticMap.getStaticMap();
		if ((	s.isTileEmpty(tileNorth))&&
				(s.isTileEmpty(tileSouth))&&
				(!boxList.isBoxOnTile(tileNorth))&&
				(!boxList.isBoxOnTile(tileSouth))) {
			return true;
		}
		return false;
	}
	
	public boolean isTileEmptyForHorizontalMove(BoxList boxList, int x, int y) {
		Coord tileWest    = new Coord(x-1,y);
		Coord tileEast    = new Coord(x+1,y);
		
		StaticMap s = StaticMap.getStaticMap();
		if ((s.isTileEmpty(tileEast))&&
				(s.isTileEmpty(tileWest))&&
				(!boxList.isBoxOnTile(tileEast))&&
				(!boxList.isBoxOnTile(tileWest))) {
			return true;
		}
		return false;
	}
	
	
	private static final char NIL   = 'x';
	private static final char U     = 'U';
	private static final char D     = 'D';	
	private static final char R     = 'R';
	private static final char L     = 'L';
	private static final char u     = 'u';
	private static final char d     = 'd';	
	private static final char r     = 'r';
	private static final char l     = 'l';
	
	public boolean isPushAllowed(BoxList boxList, Coord c, char instruction) {

		StaticMap s = StaticMap.getStaticMap();
		
		Coord newC = c.getCoordFromDirection(instruction);
		
		if (s.isTileCorner(newC)) return false;

		if (s.isDeathWallTile(newC)) return false;
		
		//Will not work!!
		//This is because there are many "adjacent" tiles that do not produce deadlocks 
		//if (s.isAdjacentTile(newC)) return false;
		
		if ((s.isTileEmpty(newC))&&(!boxList.isBoxOnTile(newC))) return true;
		

		//===========================================================
		//Code for checking two tiles (to discern if a general push is allowed).
		//===========================================================
		/*
		switch(instruction) {
		case u: 
		case d: return isTileEmptyForVerticalMove(boxList, c.x, c.y);
		case l:
		case r: return isTileEmptyForHorizontalMove(boxList, c.x, c.y);
		default: System.err.print("Invalid instruction");
		}
		//return false; //last line of method
		*/
		return false;
	}
	
	public boolean isPullAllowed(BoxList boxList, Coord c, char instruction) {

		StaticMap s = StaticMap.getStaticMap();
		
		Coord newC = c.getCoordFromDirection(instruction);
		Coord newPlayerC = newC.getCoordFromDirection(instruction);
		
		if (s.isTileCorner(newC)) 
			{
			//System.out.println("CRY! Corner error");
			return false;
			}

		if (s.isDeathWallTile(newC)) 
			{
			//System.out.println("CRY! Death wall error");
			return false;
			}
		
		//Will not work!!
		//This is because there are many "adjacent" tiles that do not produce deadlocks 
		//if (s.isAdjacentTile(newC)) return false;
		
		if ((s.isTileEmpty(newPlayerC))&&(!boxList.isBoxOnTile(newC))&&(!boxList.isBoxOnTile(newPlayerC))) 
			{
			//System.out.println("WOOAH!");
			return true;
			}
		

		//===========================================================
		//Code for checking two tiles (to discern if a general push is allowed).
		//===========================================================
		/*
		switch(instruction) {
		case u: 
		case d: return isTileEmptyForVerticalMove(boxList, c.x, c.y);
		case l:
		case r: return isTileEmptyForHorizontalMove(boxList, c.x, c.y);
		default: System.err.print("Invalid instruction");
		}
		//return false; //last line of method
		*/
		return false;
	}
	
	public boolean isPullAllowed(BoxList boxList, char instruction) {
		return isPullAllowed(boxList, this.getCoord(), instruction);
	}
	
	public boolean isPushAllowed(BoxList boxList, char instruction) {

		return isPushAllowed(boxList, this.getCoord(), instruction);
		
		/*
		
		StaticMap s = StaticMap.getStaticMap();
		
		Coord newC = this.getCoord().getCoordFromDirection(instruction);
		
		if (s.isTileCorner(newC)) return false;

		if (s.isDeathWallTile(newC)) return false;
		
		
		if ((s.isTileEmpty(newC))&&(!boxList.isBoxOnTile(newC))) return true;
		

		return false;*/
	}
	
	public Coord getCoord() {
		return position;
	}

	public int compareTo(Box o) {
		if (this.equals(o)) return 0;
		return 1;
	}
}
